package com.calvin.study.service;

import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import com.calvin.study.mapper.OrderMapper;
import com.calvin.study.rabbitmq.producer.RabbitMqProducer;

import cloud.alibaba.study.entity.base.ResponseVo;
import cloud.alibaba.study.entity.order.Order;
import cloud.alibaba.study.entity.storage.Storage;
import cloud.alibaba.study.service.BaseService;
import cloud.alibaba.study.utils.GsonUtil;
import cn.hutool.core.lang.Snowflake;
import io.seata.spring.annotation.GlobalTransactional;

@Service
public class OrderService extends BaseService {
	
	@Autowired
	private OrderMapper orderMapper;
	
	@Autowired
	private RestTemplate restTemplate;
	
	/**
	 * @Title: placeOrder   
	 * @Description: 
	 * 	1.使用seata来控制分布式事务，由于seata中对各个资源进行加锁控制，像高并发一类的操作，必然会对性能有一定损耗。
	 * @date: 2022年7月28日 上午10:10:46   
	 * @version:
	 * @param order
	 * @return
	 * @throws Exception          
	 * @throws
	 */
	@GlobalTransactional
	@Transactional
	public ResponseVo placeOrder(Order order) throws Exception {
		ResponseVo resp  = new ResponseVo();
		//1.生成订单
		orderMapper.insert(order);
		
		//2.调用库存服务，测试分布式事务
		Storage storage = new Storage();
		storage.setProductId(order.getProductId());
		storage.setUsed(order.getCount());
		
		 Map<String, Object> param = new HashMap<String, Object>();
		 param.put("storage", storage);
		
		//设置请求头
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.APPLICATION_JSON);
		HttpEntity<String> request = new HttpEntity<String>(GsonUtil.toJsonDateFormat(storage),headers);
		//远程调用库存服务
		ResponseEntity<String> respEntity  = restTemplate.postForEntity("http://service-storage/storage/reduce", request, String.class);
		//如果这里转换出现异常，订单数据回滚，库存扣减成功，@Transactional无法回滚调用服务的数据
		resp = GsonUtil.fromJson(respEntity.getBody(), ResponseVo.class, GsonUtil.DATE_FORMAT);
		//int i =1/0;
		return resp;
	}
	
	@Autowired
	private RabbitMqProducer rabbitMqProducer;
	
	public ResponseVo placeOrderV2(Order order) throws Exception {
		ResponseVo resp = (ResponseVo) execute(new TransactionService() {
			@Override
			public Object doTransaction() throws Exception {
				//1.创建订单
				orderMapper.insert(order);
				return ResponseVo.success(order);
			}

			@Override
			public void doExceptTransaction(Object obj) {
				//如果事务内方法发生异常,则不会执行该方法
				System.out.println("placeOrderV2 事务外方法执行");
				ResponseVo resp = (ResponseVo) obj;
				Order order = (Order) resp.getRespData();
				if(order.getOrderType()!=20) {
					//通知库存系统，进行库存预占(非秒杀订单)。
					rabbitMqProducer.pushToExchange("storage-event-exchange", "storage.reserved", order,String.valueOf(order.getOrderId()));
					//创建订单队列（订单付款时间为1分钟），超时后，则解除库存预占。
					rabbitMqProducer.pushToExchange("order-event-exchange","order.place.order", order,String.valueOf(order.getOrderId()));
				}
			}
		});
		return resp;
	}
	
	
	public static void main(String[] args) {
		System.out.println(new Snowflake().nextId());
	}

}
